(十)Dubbo使用多协议(hessian、rest、dubbo) 您所在的位置:网站首页 dubbo application (十)Dubbo使用多协议(hessian、rest、dubbo)

(十)Dubbo使用多协议(hessian、rest、dubbo)

#(十)Dubbo使用多协议(hessian、rest、dubbo)| 来源: 网络整理| 查看: 265

Dubbo是支持多种协议的,这里我会 演示 dubbo(默认)、hessian、rest 这三种协议。文章代码贴的比较多,代码已经上传到GitHub,见文末。

假如我有这样一个场景:

OrderService 接口有两个实现类,其中一个 OrderServiceImpl 获取的数据较小,我想通过dubbo协议调用;而另外一个 OrderServiceImpl2 获取的数据较大,我想通过 hessian协议调用,或者我想直接通过Http调用provider的接口。

这要如何配置呢?

下面来研究一下这几种协议的使用。

TODO:可以使用jmh压测不同协议传输不同的数据量,进行性能对比

项目结构:

父类pom,引入协议需要的依赖:

dubbo-samples-xml-api dubbo-samples-xml-provider dubbo-samples-xml-consumer Demo project for Spring 1.8 1.8 2.7.13 4.3.16.RELEASE 4.12 8.0.53 1.1.0.Final 4.2.0.Final org.springframework spring-framework-bom ${spring.version} pom import org.apache.dubbo dubbo-bom ${dubbo.version} pom import org.apache.dubbo dubbo-dependencies-zookeeper ${dubbo.version} pom junit junit ${junit.version} test javax.validation validation-api ${validation-api.version} org.hibernate hibernate-validator ${hibernate-validator.version} org.apache.tomcat.embed tomcat-embed-core ${tomcat.version} 1、新建api项目

新建dubbo-samples-xml-api项目

pom.xml:

org.apache.dubbo dubbo-rpc-rest org.projectlombok lombok 1.18.12

定义接口:

OrderRESTService:

public interface OrderRESTService { Order getOrderInfo(Long id); }

OrderRESTService2,一个标准的 JAX-RS rest服务:

@Consumes({MediaType.APPLICATION_JSON}) @Produces({ContentType.APPLICATION_JSON_UTF_8, ContentType.TEXT_XML_UTF_8}) @Path("order2") public interface OrderRESTService2 { @GET @Path("{id : \\d+}") Order getOrderInfo(@PathParam("id") Long id); }

OrderService:普通接口

public interface OrderService { List getOrderInfo(long orderId); }

Order:实体类

@Data @NoArgsConstructor @AllArgsConstructor public class Order implements Serializable { private static final long serialVersionUID = -3757842094691885448L; Long orderId; String orderName; } 2、创建provider

创建一个dubbo-samples-xml-provider 项目。

pom.xml:

com.dubbo dubbo-samples-xml-api 0.0.1-SNAPSHOT org.springframework spring-web org.springframework spring-context org.apache.dubbo dubbo junit junit org.apache.tomcat.embed tomcat-embed-core org.hibernate hibernate-validator org.apache.dubbo dubbo-rpc-rest org.apache.dubbo dubbo-registry-zookeeper org.apache.dubbo dubbo-rpc-hessian

创建四个实现类:

其中 OrderServiceImpl、OrderServiceImpl2 均实现 OrderService 接口,具体代码如下:

OrderServiceImpl:

@Service("orderServiceImpl") @Slf4j public class OrderServiceImpl implements OrderService { @Override public List getOrderInfo(long orderId) { log.info("OrderServiceImpl方法"); log.info("request from consumer: {}", RpcContext.getContext().getRemoteAddress()); log.info("protocol: {}",RpcContext.getContext().getProtocol()); log.info("response from provider: {}",RpcContext.getContext().getLocalAddress()); List list = new ArrayList(); Order order1 = new Order(); order1.setOrderId(199L); order1.setOrderName("MacBook Pro 13"); Order order2 = new Order(); order2.setOrderId(200L); order2.setOrderName("RTX 2060"); list.add(order1); list.add(order2); return list; } }

OrderServiceImpl2:

/** * @author 醋酸菌HaC | WebSite📶 : https://rain.baimuxym.cn * @site * @date 2021/11/17 * @Description 这是个复杂大对象,用于测试传输大包 */ @Service("orderServiceImpl2") @Slf4j public class OrderServiceImpl2 implements OrderService { @Override public List getOrderInfo(long orderId) { log.info("OrderServiceImpl2方法"); log.info("request from consumer: {}", RpcContext.getContext().getRemoteAddress()); log.info("protocol: {}",RpcContext.getContext().getProtocol()); log.info("response from provider: {}",RpcContext.getContext().getLocalAddress()); List list = new ArrayList(); for (int i = 10; i

这里声明了三种协议,协议注意不同的端口,server="tomcat" 表示使用的是内部tomcat。

Provider启动类:

public class Provider { public static void main(String[] args) throws Exception { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"spring/dubbo-provider.xml"}); context.start(); System.out.println("provider service start ......"); new CountDownLatch(1).await(); } } 3、创建consumer

创建dubbo-samples-xml-consumer项目。

pom:

com.dubbo dubbo-samples-xml-api 0.0.1-SNAPSHOT compile org.apache.dubbo dubbo org.apache.dubbo dubbo-dependencies-zookeeper pom org.springframework spring-web org.hibernate hibernate-validator org.apache.dubbo dubbo-rpc-rest org.apache.dubbo dubbo-registry-zookeeper org.apache.dubbo dubbo-rpc-hessian

dubbo-consumer.xml 配置类:

Consumer启动类:

/** * @author 醋酸菌HaC | WebSite📶 : https://rain.baimuxym.cn * @date 2021/11/22 * @Description consumer启动类 */ public class Consumer { public static void main(String[] args) throws Exception { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"spring/dubbo-consumer.xml"}); context.start(); System.out.println("consumer start....."); // dubbo OrderService orderService1 = context.getBean("orderServiceImpl", OrderService.class); // hessian OrderService orderService2 = context.getBean("orderServiceImpl2", OrderService.class); // rest OrderRESTService2 orderRESTService2 = context.getBean("orderRESTService2", OrderRESTService2.class); while (true) { System.in.read(); RpcContext rpcContext = RpcContext.getContext(); System.out.println("SUCCESS: got order list " + orderService1.getOrderInfo(1L)); System.out.println("SUCCESS: got order list" + orderService2.getOrderInfo(1L)); System.out.println("SUCCESS: got order " + orderRESTService2.getOrderInfo(1L)); // rest String port = "7777"; getOrder("http://localhost:" + port + "/services/order/2"); } } /** * 走http调用 * @param url */ private static void getOrder(String url) { Client client = ClientBuilder.newClient(); WebTarget target = client.target(url); Response response = target.request().get(); try { if (response.getStatus() != 200) { throw new RuntimeException("Failed with HTTP error code : " + response.getStatus()); } System.out.println("SUCCESS: got result: " + response.readEntity(Order.class)); } finally { response.close(); client.close(); } } } 4、测试

执行 provider 测试类,打开dubbo-admin 项目(dubbo官方的可视化面板,需要自行搭建),可以看到有四个提供接口:

点击某个接口,可以看到详细的信息:

启动consumer测试类,可以看到日志:

consumer日志:

SUCCESS: got order list [Order(orderId=199, orderName=MacBook Pro 13), Order(orderId=200, orderName=RTX 2060)] SUCCESS: got order list[Order(orderId=10, orderName=MacBook Pro 10), Order(orderId=11, orderName=MacBook Pro 11), Order(orderId=12, orderName=MacBook Pro 12), Order(orderId=13, orderName=MacBook Pro 13), Order(orderId=14, orderName=MacBook Pro 14), Order(orderId=15, orderName=MacBook Pro 15), Order(orderId=16, orderName=MacBook Pro 16), Order(orderId=17, orderName=MacBook Pro 17), Order(orderId=18, orderName=MacBook Pro 18), Order(orderId=19, orderName=MacBook Pro 19), Order(orderId=20, orderName=MacBook Pro 20)] SUCCESS: got order Order(orderId=1, orderName=MacBook Pro) SUCCESS: got result: Order(orderId=2, orderName=MacBook Air2)

provider日志:

# 这里是dubbo协议调用 2021-12-23 15:29.33 [DubboServerHandler-172.16.44.48:20883-thread-23] -- [ INFO] - impl.OrderServiceImpl: OrderServiceImpl方法 2021-12-23 15:29.33 [DubboServerHandler-172.16.44.48:20883-thread-23] -- [ INFO] - impl.OrderServiceImpl: request from consumer: /172.16.44.48:54311 2021-12-23 15:29.33 [DubboServerHandler-172.16.44.48:20883-thread-23] -- [ INFO] - impl.OrderServiceImpl: protocol: null 2021-12-23 15:29.33 [DubboServerHandler-172.16.44.48:20883-thread-23] -- [ INFO] - impl.OrderServiceImpl: response from provider: 172.16.44.48:20883 # 这里是hessian协议调用 2021-12-23 15:29.33 [http-nio-8888-exec-6] -- [ INFO] - impl.OrderServiceImpl2: OrderServiceImpl2方法 2021-12-23 15:29.33 [http-nio-8888-exec-6] -- [ INFO] - impl.OrderServiceImpl2: request from consumer: 172.16.44.48:54314 2021-12-23 15:29.33 [http-nio-8888-exec-6] -- [ INFO] - impl.OrderServiceImpl2: protocol: dubbo 2021-12-23 15:29.33 [http-nio-8888-exec-6] -- [ INFO] - impl.OrderServiceImpl2: response from provider: 172.16.44.48:8888 # 这里是rest协议调用 2021-12-23 15:29.33 [http-nio-7777-exec-1] -- [ INFO] - rest.OrderRESTServiceImpl2: 这是在接口上声明的rest 2021-12-23 15:29.33 [http-nio-7777-exec-1] -- [ INFO] - rest.OrderRESTServiceImpl2: request from consumer: 172.16.44.48:54315 2021-12-23 15:29.33 [http-nio-7777-exec-1] -- [ INFO] - rest.OrderRESTServiceImpl2: protocol: dubbo 2021-12-23 15:29.33 [http-nio-7777-exec-1] -- [ INFO] - rest.OrderRESTServiceImpl2: response from provider: 172.16.44.48:7777 # 这里是http协议调用 2021-12-23 15:29.33 [http-nio-7777-exec-2] -- [ INFO] - rest.OrderRESTServiceImpl: 这是在实现类上声明的rest 2021-12-23 15:29.33 [http-nio-7777-exec-2] -- [ INFO] - rest.OrderRESTServiceImpl: request from consumer: 127.0.0.1:54316 2021-12-23 15:29.33 [http-nio-7777-exec-2] -- [ INFO] - rest.OrderRESTServiceImpl: protocol: dubbo 2021-12-23 15:29.33 [http-nio-7777-exec-2] -- [ INFO] - rest.OrderRESTServiceImpl: response from provider: 172.16.44.48:7777

在dubbo-admin可以看到有三个消费者(rest、hessian、dubbo 各一个协议的消费者,第四个是http直连的):

5、其他 5.1、rest

dubbo支持rest(dubbo集成了JAX-RS)在使用上,这里和spring有异曲同工之妙,简单使用几个JAX-RS注解就可以使用了,如:

@Path("users") public class UserServiceImpl implements UserService { @POST @Path("register") @Consumes({MediaType.APPLICATION_JSON}) public void registerUser(User user) { // save the user... } }

@Path("users"):指定访问UserService的URL相对路径是/users,即http://localhost:8080/users

@Path("register"):指定访问registerUser()方法的URL相对路径是/register,再结合上一个@Path为UserService指定的路径,则调用UserService.register()的完整路径为http://localhost:8080/users/register

@POST:指定访问registerUser()用HTTP POST方法

@Consumes({MediaType.APPLICATION_JSON}):指定registerUser()接收JSON格式的数据。REST框架会自动将JSON数据反序列化为User对象

然后在配置中声明需要暴露的服务接口即可:

5.2、踩坑:

使用 rest 协议的时候,启动consumer 发现报错:

You must use at least one, but no more than one http method annotation on: public abstract

原因是 实现类使用 @Path、@Consumes、@Produces 注解:

@Service("orderRESTServiceImpl") @Path("provider") @Consumes({MediaType.APPLICATION_JSON, MediaType.TEXT_XML}) @Produces({ContentType.APPLICATION_JSON_UTF_8, ContentType.TEXT_XML_UTF_8}) public class OrderRESTServiceImpl implements OrderRESTService {

consumer.xml 又配置了:

使用了JAX-RS 的注解,本来就提供REST服务,所以就会出现两个REST,提示报错。

解决方法:

使用JAX-RS的注解到接口上,而不是实现类 使用http直连的方法访问即可,rest协议可以直接使用 http 访问

那 Annotation放在接口类还是实现类?

在一般应用中, 建议放在实现类,便于维护,又不用污染接口,万一该接口有多个实现类就....

如果接口和实现类都同时添加了annotation,则实现类的annotation配置会生效,接口上的annotation被直接忽略。

当然你都放在实现类了,在consumer的配置文件,就不要使用 protocol="rest" 这种方式调用了,直接使用http连接就可以了。

5.3、rest、hessian

这两个协议需要依赖 servlet 容器,当然你也可以使用外部的servlet容器,只需要在你的web.xml配置:

contextConfigLocation classpath:/spring/dubbo-provider-rest.xml org.apache.dubbo.remoting.http.servlet.BootstrapListener org.springframework.web.context.ContextLoaderListener dispatcher org.apache.dubbo.remoting.http.servlet.DispatcherServlet 1 dispatcher /services/*

在配置文件中声明:

contextpath 必须要和 web.xml 配置的 url-pattern 一致

端口也必须要和外部servlet容器一致

未来TODO:

参考:

使用 rest 协议:https://dangdangdotcom.github.io/dubbox/rest.html


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有